package com.ng.framework.util;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;

public class NGUtil {

	public static final SimpleDateFormat ddMMyyyy_dateFormat = new SimpleDateFormat("dd/MM/yyyy");

	public static final SimpleDateFormat yyyyMMdd_dateFormat = new SimpleDateFormat("yyyyMMdd");

	public static final SimpleDateFormat yyyyMMdd_HHmmss_dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	public static final SimpleDateFormat ddMMM_dateFormat = new SimpleDateFormat("dd/MMM");

	public static final DecimalFormat $0_00 = new DecimalFormat("$ 0.00");

	public static final DecimalFormat PERCENT = new DecimalFormat("% 0.000");

	public static final NumberFormat numberFormat = NumberFormat.getInstance(Locale.GERMAN);

	public static Date getDateWithTime(Date anyDate, String hhmmss) throws ParseException {

		Calendar calendar = Calendar.getInstance();

		String[] time = hhmmss.split(":");

		Integer hours = Integer.valueOf(time[0]);
		Integer minutes = Integer.valueOf(time[1]);
		Integer seconds = Integer.valueOf(time[2]);

		Long miliseconds = (long) (1000 * (seconds + 60 * minutes + 60 * 60 * hours));

		String anyDateString = ddMMyyyy_dateFormat.format(anyDate);
		Date anyDateParsed = ddMMyyyy_dateFormat.parse(anyDateString);

		calendar.setTimeInMillis((anyDateParsed.getTime() + miliseconds));

		return calendar.getTime();
	}

	public static Date getNow(final TimeZone timeZone) {
		final Calendar now = Calendar.getInstance();
		Calendar converted = new GregorianCalendar(timeZone);
		converted.setTimeInMillis(now.getTimeInMillis() + timeZone.getOffset(now.getTimeInMillis())
				- TimeZone.getDefault().getOffset(now.getTimeInMillis()));

		return converted.getTime();
	}

	public static Date getNow() {
		TimeZone timeZone = TimeZone.getTimeZone("GMT-3:00");
		return getNow(timeZone);
	}

	public static Double roundDouble(Double doubleNumber, int decimalPlace) {
		BigDecimal bd = new BigDecimal(doubleNumber);
		bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_DOWN);
		return bd.doubleValue();
	}

	public static Double multiplyDouble(Double doubleA, Double doubleB, int decimalPlace) {

		BigDecimal bdA = new BigDecimal(doubleA);
		BigDecimal bdB = new BigDecimal(doubleB);

		BigDecimal bdC = bdA.multiply(bdB);
		bdC = bdC.setScale(decimalPlace, BigDecimal.ROUND_HALF_DOWN);

		return bdC.doubleValue();
	}

	public static String formatDouble(Double doubleValue) {

		return numberFormat.format(doubleValue);

	}

	public static Double parseDouble(String doubleAsString) {

		Number doubleValue;
		try {
			doubleValue = numberFormat.parse(doubleAsString);
			return doubleValue.doubleValue();
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;

	}

	public static List<Date> getDatesBetween(Date since, Date to, int unit, int amount, boolean includeTo) {

		List<Date> dates = new ArrayList<Date>();

		Calendar pivot = Calendar.getInstance();
		pivot.setTime(since);

		while (pivot.getTime().before(to)) {
			dates.add(pivot.getTime());
			pivot.add(unit, amount);
		}
		if (includeTo) {
			dates.add(to);
		}

		return dates;

	}

	public static Date addTime(Date since, int unit, int amount) {
		Calendar pivot = Calendar.getInstance();
		pivot.setTime(since);
		pivot.add(unit, amount);
		return pivot.getTime();
	}

	public static Double getPercent(Double numerador, Double denominador, int decimalPlace) {

		double div = numerador / denominador;

		double percent = div * 100;

		return roundDouble(percent, decimalPlace);
	}

	public static void wait(Long timeMillis) {

		try {
			Thread.sleep(timeMillis);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}

	public static Double fractionToDouble(String fraction) {

		String terminos[] = fraction.split(" ");

		if (terminos.length == 1) {

			String partes[] = terminos[0].split("/");
			int numerador = Integer.valueOf(partes[0]);
			int denominador = Integer.valueOf(partes[1]);

			return ((double) numerador / (double) denominador);

		} else {
			int parteEntera = Integer.parseInt(terminos[0]);
			String fraccionaria = terminos[1];
			return parteEntera + fractionToDouble(fraccionaria);
		}

	}

	public static boolean isInteger(double number) {
		if (number % 2 == 0 || (number + 1) % 2 == 0) {
			return true;
		}
		return false;
	}

	public static String doubleToFraction(double doubleValue, boolean extendedMode) {

		String fraction = doubleToFraction(doubleValue);

		if (extendedMode && fraction.split("/").length == 2) {

			String partes[] = fraction.split("/");
			int numerador = Integer.valueOf(partes[0]);
			int denominador = Integer.valueOf(partes[1]);

			if (!(numerador < denominador)) {

				int division = numerador / denominador;
				int resto = numerador % denominador;

				if (resto == 0) {
					return String.valueOf(division);
				} else {
					return division + " " + resto + "/" + denominador;
				}

			}

		}

		return fraction;

	}

	public static String doubleToFraction(double doubleValue) {
		// we get the whole part
		int whole = (int) doubleValue;
		// we get the rest
		// double rest = doubleValue - whole;
		double rest = BigDecimal.valueOf(doubleValue).add(BigDecimal.valueOf(-1 * whole)).doubleValue();
		int numerator = 1, denominator = 1;
		// if the whole part of the number is greater than 0
		// we'll try to transform the rest of the number to an Integer
		// by multiplying the number until it become an integer
		if (whole >= 1) {
			for (int i = 2;; i++) {
				/*
				 * when we find the "Integer" number(it'll be the numerator) we also found the denominator(i,which is the number
				 * that transforms the number to integer) For example if we have the number = 2.5 when it is multiplied by 2 now
				 * it's 5 and it's integer, now we have the numerator(the number (2.5)*i(2) = 5) and the denominator i = 2
				 */
				if (isInteger(rest * (double) i)) {
					numerator = (int) (rest * (double) i);
					denominator = i;
					break;
				}
				if (i > 10000) {
					// if i is greater than 10000 it's posible that the number is irrational
					// and it can't be represented as a fractional number
					return doubleValue + "";
				}
			}
			// if we have the number 3.5 the whole part is 3 then we have the rest represented in fraction 0.5 = 1/2
			// so we have a mixed fraction 3+1/2 = 7/2
			numerator = (whole * denominator) + numerator;
		} else {
			// If not we'll try to transform the original number to an integer
			// with the same process
			for (int i = 2;; i++) {
				if (isInteger(doubleValue * (double) i)) {
					numerator = (int) (doubleValue * (double) i);
					denominator = i;
					break;
				}
				if (i > 10000) {
					return doubleValue + "";
				}
			}
		}
		return numerator + "/" + denominator;
	}

	public static boolean validateDouble(final String s) {
		boolean valid = true;

		try {
			Double.parseDouble(s);
		} catch (NumberFormatException e) {
			valid = false;
		}

		return valid;
	}

}
